using System;
using System.IO;
using Microsoft.Management.Infrastructure;
using System.Security.Cryptography;
using System.Text;
using System.Text.Json;

namespace LicenceManager.Core
{
    public class LicenceService : ILicenceService
    {
        private readonly byte[] _encryptionKey;
        private readonly byte[] _salt = new byte[32]; // 256位随机盐值
        public LicenceService()
        {
            // 从环境变量获取密码，如果没有则使用默认值(仅用于开发环境)
            var password = "LenZen.123!@#";

            // 使用硬件信息作为盐值以确保加密解密一致性
            _salt = Encoding.UTF8.GetBytes(GetHardwareId());
            _encryptionKey = GenerateAesKeyFromPassword(password, _salt, 256);
        }

        byte[] GenerateAesKeyFromPassword(string password, byte[] salt, int keySize)
        {
            // 使用更高的迭代次数(100000次)增强安全性
            using (
                var pbkdf2 = new Rfc2898DeriveBytes(
                    password,
                    salt,
                    100000,
                    HashAlgorithmName.SHA512
                )
            )
            {
                return pbkdf2.GetBytes(keySize / 8);
            }
        }

        public void GenerateLicence(string hardwareId, DateTime expiryDate, string filePath)
        {
            var licenceData = new LicenceData
            {
                HardwareId = hardwareId,
                ExpiryDate = expiryDate,
                GeneratedDate = DateTime.Now,
            };

            using (var stream = new FileStream(filePath, FileMode.Create))
            {
                var encryptedData = EncryptData(licenceData);
                stream.Write(encryptedData, 0, encryptedData.Length);
            }
        }

        public string ValidateLicence(string filePath = "licence.dat")
        {
            if (!File.Exists(filePath))
                return "授权文件不存在";

            try
            {
                var fileData = File.ReadAllBytes(filePath);
                var licenceData = DecryptData(fileData);

                // 检查硬件ID是否匹配
                if (licenceData.HardwareId != GetHardwareId())
                    return "授权与当前硬件不匹配";

                // 检查是否过期
                if (licenceData.ExpiryDate < DateTime.Now)
                    return $"授权已于 {licenceData.ExpiryDate:yyyy-MM-dd HH:mm:ss} 过期";

                return string.Empty;
            }
            catch (CryptographicException ex)
            {
                return "授权文件损坏或无效";
            }
            catch (JsonException ex)
            {
                return "授权格式不正确";
            }
            catch (Exception ex)
            {
                return $"验证过程中发生异常 - {ex.Message}";
            }
        }

        public string GetHardwareId()
        {
            // 使用CPU ID和MAC地址生成硬件ID
            var cpuId = GetWmiProperty("Win32_Processor", "ProcessorId");
            var macAddress = GetMacAddress();

            using (var sha256 = SHA256.Create())
            {
                var hashBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes($"{cpuId}-{macAddress}"));
                return BitConverter.ToString(hashBytes).Replace("-", "");
            }
        }

        private byte[] EncryptData(LicenceData data)
        {
            using (var aes = Aes.Create())
            {
                aes.Key = _encryptionKey;
                aes.GenerateIV(); // 生成随机IV

                // 先序列化为JSON
                var json = JsonSerializer.SerializeToUtf8Bytes(data);

                using (var encryptor = aes.CreateEncryptor(aes.Key, aes.IV))
                using (var ms = new MemoryStream())
                {
                    // 写入IV
                    ms.Write(aes.IV, 0, aes.IV.Length);

                    // 然后加密数据
                    using (var cs = new CryptoStream(ms, encryptor, CryptoStreamMode.Write))
                    {
                        cs.Write(json, 0, json.Length);
                    }
                    return ms.ToArray();
                }
            }
        }

        private LicenceData DecryptData(byte[] encryptedData)
        {
            using (var aes = Aes.Create())
            {
                aes.Key = _encryptionKey;
                // 从加密数据前16字节读取IV
                var iv = new byte[16];
                Array.Copy(encryptedData, 0, iv, 0, 16);
                aes.IV = iv;

                // 创建新的数组只包含加密数据(去掉IV部分)
                var cipherData = new byte[encryptedData.Length - 16];
                Array.Copy(encryptedData, 16, cipherData, 0, cipherData.Length);

                using (var decryptor = aes.CreateDecryptor(aes.Key, aes.IV))
                using (var ms = new MemoryStream(cipherData))
                using (var cs = new CryptoStream(ms, decryptor, CryptoStreamMode.Read))
                using (var reader = new StreamReader(cs))
                {
                    var json = reader.ReadToEnd();
                    if (string.IsNullOrEmpty(json))
                    {
                        throw new CryptographicException("解密数据为空");
                    }
                    return JsonSerializer.Deserialize<LicenceData>(json)!;
                }
            }
        }

        private string GetMacAddress()
        {
            try
            {
                return GetWmiProperty("Win32_NetworkAdapterConfiguration", "MACAddress")
                    .Split(new[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries)
                    .FirstOrDefault() ?? string.Empty;
            }
            catch
            {
                return string.Empty;
            }
        }


        /// <summary>
        /// 通过CIM/WMI查询获取属性值
        /// </summary>
        /// <param name="className">WMI类名</param>
        /// <param name="propertyName">属性名</param>
        /// <returns>属性值，如果获取失败则抛出异常</returns>
        static string GetWmiProperty(string className, string propertyName)
        {
            try
            {
                using (CimSession session = CimSession.Create(null))
                {
                    var query = $"SELECT {propertyName} FROM {className}";
                    var instances = session.QueryInstances(@"root\cimv2", "WQL", query);
                    foreach (var instance in instances)
                    {
                        var property = instance.CimInstanceProperties[propertyName];
                        if (property != null && property.Value != null)
                        {
                            return property.Value.ToString();
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                throw ex;
            }
            throw new Exception("不支持此类型");
        }
    }

    [Serializable]
    public class LicenceData
    {
        public string HardwareId { get; set; } = string.Empty;
        public DateTime ExpiryDate { get; set; }
        public DateTime GeneratedDate { get; set; }
    }
}
